package xmlParser;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import mover.Mass;
import mover.Spring;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Creates an XmlParser that can parse an XML file. 
 * @author Ga-Young Joung and Perry Zheng
 *
 */
public class XmlParser {
	private List myNodesList;
	private List mySpringsList;
	private List myMusclesList;
	private Map<String, Mass> map; 
	Document dom;
	public static String ADDRESS = "example.xml";
	public static int SIZE = 50;
	
	/**
	 * Creates an XmlParser that keeps an Nodes list, a Springs list, and a Muscles list
	 */
	public XmlParser(){
		myNodesList = new ArrayList();
		mySpringsList = new ArrayList();
		myMusclesList = new ArrayList();
		map = new HashMap<String, Mass>();
	}
	
	/**
	 * Get nodes list method
	 * @return the nodes list
	 */
	public List getNodesList() {
		return myNodesList;
	}
	
	/**
	 * Get Springs list
	 * @return the springs list
	 */
	public List getSpringsList() {
		return mySpringsList;
	}
	
	/**
	 * Get Muscles list
	 * @return the muscles list
	 */
	public List myMusclesList() {
		return myMusclesList;
	}
	
	/**
	 * Parse a XML file
	 * @param file
	 */
	public void parseXmlFile(File file){
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder db = dbf.newDocumentBuilder();
			dom = db.parse(file);
		}catch(ParserConfigurationException pce) {
			pce.printStackTrace();
		}catch(SAXException se) {
			se.printStackTrace();
		}catch(IOException ioe) {
			ioe.printStackTrace();
		}
	}
	
	/**
	 * Parse a XML file with a certain address
	 * @param address
	 */
	public void parseXmlFile(String address) {
		parseXmlFile(new File(address));
	}
	
	/**
	 * Parse the document,gettings the Nodes list, Springs list, and Muscles list
	 */
	public void parseDocument(){
		Element docElement = dom.getDocumentElement();
		NodeList nodes = docElement.getElementsByTagName("mass");
		NodeList springs = docElement.getElementsByTagName("spring");
		NodeList muscles = docElement.getElementsByTagName("muscle");
		if(nodes!=null && nodes.getLength() > 0) {
			for(int i = 0 ; i < nodes.getLength();i++) {
				Element element  = (Element)nodes.item(i);
				myNodesList.add(getMass(element));
				
			}
		}
		
		if(springs!=null && springs.getLength()>0) {
			for(int i=0; i<springs.getLength();i++) {
				Element element = (Element)springs.item(i);
				mySpringsList.add(getSpring(element));
			}
		}
		if(muscles!=null && muscles.getLength()>0) {
			for(int i=0; i<muscles.getLength();i++) {
				Element element = (Element)muscles.item(i);
				myMusclesList.add(getMuscle(element));
			}
		}
	}
	
	/**
	 * Get the spring from an XML-tree element
	 * @param e - an XML-tree element
	 * @return the a Spring object associated with the parameters set in that element
	 */
	public Spring getSpring(Element e) {
		String node1 = e.getAttribute("a");
		String node2 = e.getAttribute("b");
		Double restLength = Double.parseDouble(e.getAttribute("restlength"));
		Double springyness = Double.parseDouble(e.getAttribute("springyness"));
		return new Spring(map.get(node1), map.get(node2), restLength, springyness);
	}
	
	/**
	 * Get the muscle object from an XML-tree element
	 * @param e - an XML-tree element
	 * @return a Muscle object associated with the parameters set in that element
	 */
	public Muscle getMuscle(Element e) {
		String node1key = e.getAttribute("a");
		String node2key = e.getAttribute("b");
		Double restLength = Double.parseDouble(e.getAttribute("restlength"));
		Double amplitude = Double.parseDouble(e.getAttribute("amplitude"));
		Double phase = Double.parseDouble(e.getAttribute("phase"));
		return new Muscle(map.get(node1key), map.get(node2key), restLength, amplitude, phase);
	}

	/**
	 * Get the mass object from an XML-tree element
	 * @param e - an XML-tree element
	 * @return a Mass object associated with the parameters set in that element
	 */
	public Mass getMass(Element e) {
		String id = e.getAttribute("id");
		double x = Double.parseDouble(e.getAttribute("x"));
		double y = Double.parseDouble(e.getAttribute("y"));
		double weight = Integer.parseInt(e.getAttribute("weight"));
		Mass mass = new Mass(new Point2D.Double(x,y), new Dimension(SIZE,SIZE), Color.GREEN, weight, 0);
		map.put(id, mass);
		return mass;
	}
	
	/**
	 * Pring out the parsed content
	 */
	private void printData(){
		Iterator it1 = myNodesList.iterator();
		Iterator it2 = mySpringsList.iterator();
		Iterator it3 = myMusclesList.iterator();
		print("Nodes:");
		while(it1.hasNext()) {
			print(it1.next());
		}
		print("springs:");
		while(it2.hasNext()) {
			System.out.println(it2.next());
		}
		print("muscles:");
		while(it3.hasNext()) {
			System.out.println(it3.next());
		}
	}
	
	/**
	 * A shortcut for printing an object 
	 * @param o an object
	 */
	public void print(Object o) {
		System.out.println(o);
	}
	
	public static void main(String[] args) {
		XmlParser parser = new XmlParser();
		parser.parseXmlFile(ADDRESS);
		parser.parseDocument();
		parser.printData();
	}
	
}

